<script lang="ts" setup>
import { ref, onMounted, watch } from 'vue'
import { dayjs, ElMessage, ElMessageBox } from 'element-plus'
import { debounce } from 'lodash-es'
import { BarBaseOptions, LineBaseOptions, PieBaseOptions } from '@/utils/echartsOptions'
import { chartEchart } from '@/api/zhinengwenshu/chat'
import MessageItems from './component/messageItems.vue'

const userInfo = ref({
	nickname: 'chat',
	headimgurl: '',
	uid: 'chat-1',
	token_max: 0,
	token_used: 0,
})

// 当前会话消息
const messages = ref([
	{
		type: 'text',
		list: [
			{
				content: '你好，我是chat, 很高兴遇见你！',
				type: 'text',
			},
		],
		time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
	},
])

//历史会话消息
const histroyMessages = ref([])

// 输入的文字
const inputText = ref('')

// 等待消息loading
const showLoading = ref(false)

// 发送消息的时间
const currentTime = ref('')

// 语音识别loading
const speechLoading = ref(false)

// speech 语音 text 文本
const inputType = ref('text')

// 语音识别的文字
const speechText = ref('')

// 是否正在说话
const isSpeaking = ref(false)

// 录音对象
const rec = ref(null)

// 录音的文件流
const recBlob = ref(null)

// prompt模板文字
const prompt = ref(null)

const isMobile = ref(false)

// 聊天窗口滚动到底部
const scrollToBottom = debounce(
	() => {
		// console.log('滚动到底部')
		const chatWrap = document.getElementById('chatWrap')
		const documentHeight = Math.max(chatWrap.clientHeight, chatWrap.scrollHeight, chatWrap.offsetHeight)
		chatWrap.scrollTo({
			top: documentHeight,
			behavior: 'smooth',
		})
	},
	100,
	// {
	// 	leading: true,
	// }
)

// 发送消息
function clickSendButton(event: any) {
	if (showLoading.value) {
		ElMessage.warning('回复加载中，请稍后发送')
		return
	}
	event.preventDefault()

	if (!inputText.value && !speechText.value) {
		ElMessage.warning('请输入您想说的')
		return
	}
	if (inputText.value || speechText.value) {
		const text = inputText.value || speechText.value
		addMessage({
			isUser: true,
			question: text,
			type: 'text',
		})
		currentTime.value = dayjs().format('YYYY-MM-DD HH:mm:ss')
		showLoading.value = true
		sendMessage(inputText.value)
	}
}

// 向对话队列中添加消息
function addMessage({ isUser, question, data, type }) {
	let message = {}
	if (type === 'chart') {
		message = {
			list: [
				{
					content: {
						id: 'chart' + Math.floor(Math.random() * new Date().getTime()),
						question: question,
						data: data,
					},
					type: type,
				},
			],
			isUser: isUser,
			time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
		}
	} else {
		message = {
			list: [{ content: question, type: 'text' }],
			isUser: isUser,
			time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
		}
	}
	messages.value.push(message)
	console.log(messages.value, 'messages')
	scrollToBottom()
}

const mockData = {
	status: 200,
	message: '操作成功!',
	data: {
		msg: 'success',
		currentTime: 1742519375409,
		code: '0',
		data: [
			{
				data: [
					{
						name: '徐九',
						value: 550000,
					},
					{
						name: '徐七',
						value: 350000,
					},
					{
						name: '徐六',
						value: 250000,
					},
					{
						name: '徐三',
						value: 250000,
					},
					{
						name: '苏七',
						value: 150000,
					},
					{
						name: '王五',
						value: 150000,
					},
					{
						name: '徐二',
						value: 45000,
					},
					{
						name: '徐八',
						value: 42000,
					},
					{
						name: '李四',
						value: 35000,
					},
					{
						name: '朱六',
						value: 35000,
					},
					{
						name: '徐四',
						value: 12000,
					},
					{
						name: '徐一',
						value: 12000,
					},
					{
						name: '徐五',
						value: 12000,
					},
					{
						name: '陈二',
						value: 2000,
					},
					{
						name: '张三',
						value: 1500,
					},
				],
				title: '客户总积分',
				xAxis: [
					'徐九',
					'徐七',
					'徐六',
					'徐三',
					'苏七',
					'王五',
					'徐二',
					'徐八',
					'李四',
					'朱六',
					'徐四',
					'徐一',
					'徐五',
					'陈二',
					'张三',
				],
				yAxis: [
					550000, 350000, 250000, 250000, 150000, 150000, 45000, 42000, 35000, 35000, 12000, 12000, 12000, 2000, 1500,
				],
				series: [
					{
						name: '总积分',
						type: 'bar',
						data: [
							550000, 350000, 250000, 250000, 150000, 150000, 45000, 42000, 35000, 35000, 12000, 12000, 12000, 2000,
							1500,
						],
					},
				],
				legend: {
					data: ['总积分'],
				},
				type: 'bar',
			},
		],
	},
	timestamp: 1742519375412,
}
// 给服务器发送消息
function sendMessage(text) {
	const params = {
		question: text,
	}
	// chartEchart(params)
	// 	.then((res) => {
	// 		if (res.data) {
	// 			inputText.value = ''
	// 			speechText.value = ''
	// 			isSpeaking.value = false
	// 			recBlob.value = false
	// 			console.log(res.data.data[0], 'res.data.data[0]')
	// 			getMessage(res.data.data[0])
	// 		}
	// 	})
	// 	.catch(() => {
	// 		showLoading.value = false
	// 		addMessage({
	// 			isUser: false,
	// 			question: '服务器繁忙，请再试一次！',
	// 			type: 'text',
	// 		})
	// 	})

	// mock
	inputText.value = ''
	speechText.value = ''
	isSpeaking.value = false
	recBlob.value = false
	getMessage(mockData.data.data[0])
}
// 加载历史会话？
function getHistory() {
	if (localStorage.getItem('messagesList')) {
		const obj = JSON.parse(localStorage.getItem('messagesList'))
		if (!userInfo.value?.uid) return
		let historyMsg = obj[userInfo.value.uid]
		if (historyMsg?.length) {
			ElMessageBox.confirm(`是否加载历史会话？`, '提示', {
				confirmButtonText: '确定',
				cancelButtonText: '取消',
				type: 'info',
				closeOnClickModal: false,
				closeOnHashChange: true,
				customClass: 'histroy-confirm',
			}).then(() => {
				histroyMessages.value = [...historyMsg]
				scrollToBottom()
			})
		}
	}
}
// 接口回参整理
function getMessage(res) {
	console.log(res, 'getMessage')
	if (res.answer) {
		// 回复
		addMessage({
			isUser: false,
			question: res.answer,
			type: 'text',
		})
	}
	if (res?.usage?.total) {
		userInfo.value.token_used += res.usage.total
	}
	addMessage({
		isUser: false,
		question: res.question,
		data: convertData(res),
		type: 'chart',
	})
	showLoading.value = false
}
// 生成图表需要的格式
function convertData(source) {
	const { data, type, xAxis: XData = [], yAxis = [], title = '', series = [], legend = {} } = source
	let options = {}
	const YData = [yAxis] || []
	console.log('YData', YData)

	if (type === 'bar' || type === '柱状图') {
		options = new BarBaseOptions(XData, series, title, legend).options
	} else if (type === 'line' || type === '折线图') {
		options = new LineBaseOptions(XData, series, title, legend).options
	} else if (type === 'pie' || type === '饼状图') {
		options = new PieBaseOptions(data, title, legend).options
	}
	return options
}

onMounted(() => {
	watch(
		() => messages.value,
		(nVal, oVal) => {
			// localStorage.setItem("messagesList", JSON.stringify(messages.value));
			let obj = JSON.parse(localStorage.getItem('messagesList')) || {}
			if (obj && userInfo.value?.uid) {
				obj[userInfo.value.uid] = [...histroyMessages.value, ...nVal]
			}
			localStorage.setItem('messagesList', JSON.stringify(obj))
		},
		{
			deep: true,
		}
	)
	getHistory()
})
</script>
<template>
	<div class="chat-page">
		<div class="message-container" id="chatWrap">
			<MessageItems :messages="histroyMessages" :isHistory="true" :userAvatar="userInfo?.headimgurl" />
			<MessageItems :messages="messages" :isHistory="false" :userAvatar="userInfo?.headimgurl" />
			<MessageItems :isLoadingMode="true" v-if="showLoading" :userAvatar="userInfo?.headimgurl" />
		</div>
		<div class="wave-wrap" v-if="userInfo && inputType == 'speech'">
			<div :class="isSpeaking ? 'active wave' : 'wave'"></div>
			<div :class="isSpeaking ? 'active wave' : 'wave'"></div>
			<div :class="isSpeaking ? 'active wave' : 'wave'"></div>
			<div :class="isSpeaking ? 'active wave' : 'wave'"></div>
			<div :class="isSpeaking ? 'active wave' : 'wave'"></div>
		</div>
		<div class="container">
			<!-- 语音输入 -->
			<div class="input-box speech box-shadow-top" v-if="inputType == 'speech'">
				<!-- 移动端 -->
				<button
					v-if="isMobile"
					class="play"
					:class="isSpeaking ? 'speaking' : ''"
					title="语音输入"
					@touchstart.prevent="speechInput"
					@touchend.prevent="recStop"
					v-loading="showLoading || speechLoading"
				>
					<i class="el-icon-microphone"></i><span>{{ isSpeaking ? '松开发送' : '按住说话' }}</span>
				</button>
				<!-- PC端 -->
				<button
					v-else-if="!isMobile"
					class="play"
					:class="isSpeaking ? 'speaking' : ''"
					title="语音输入"
					@mousedown.prevent="speechInput"
					@mouseup.prevent="recStop"
					@mouseleave="recStop"
					v-loading="showLoading || speechLoading"
				>
					<i class="el-icon-microphone"></i><span>{{ isSpeaking ? '松开发送' : '按住说话' }}</span>
				</button>
			</div>
			<!-- 文本输入 -->
			<div class="input-box text box-shadow-top" v-else-if="inputType == 'text'" v-loading="showLoading">
				<el-input
					v-model="inputText"
					:disabled="showLoading"
					resize="none"
					:autosize="{
						minRows: 1,
						maxRows: 3,
					}"
					type="textarea"
					placeholder="请输入……"
					ref="messageInput"
					@keydown.enter="clickSendButton"
					@focus="scrollToBottom"
				/>

				<el-button title="发送" @click="clickSendButton" type="primary" class="send-button" icon="el-icon-s-promotion">
					<el-icon><Promotion /></el-icon>
				</el-button>
			</div>
		</div>
	</div>
</template>
<style lang="scss" scoped>
$color: #e91e63;
$ruler: 16px;
$color-red: #ae1100;
$color-bg: #ebecf0;
$color-shadow: #babecc;
$color-white: #fff;

.chat-page {
	width: 100%;
	font-size: 14px;
	height: 100%;
	margin: 0 auto;
	display: flex;
	align-items: center;
	flex-direction: column;
	background-color: #f3f5fa;
	.container {
		width: 100%;
		display: flex;
		justify-content: space-around;
		position: sticky;
		bottom: 20px;

		::v-deep(.el-loading-mask) {
			border-radius: 16px;
		}
	}

	.box-shadow-top {
		box-shadow: 0 -2px 2px rgba(120, 120, 120, 0.2);
	}

	.box-shadow-bottom {
		box-shadow: 0 5px 5px rgba(120, 120, 120, 0.2);
	}

	.message-container {
		width: 100%;
		flex: 1;
		// height: calc(100% - 180px);
		padding: 20px 0;
		// overflow: hidden auto;
		transition: all 0.3s;
		overflow-y: auto;
	}

	.message-line {
		width: 100%;
		border-top: 1px solid #f0f0f0;
		height: 0;
	}

	.input-box {
		margin: 0 auto;
		width: 100%;
		height: 98px;
		max-width: 780px;
		padding: 0 18px;
		display: flex;
		align-items: center;
		justify-content: space-between;
		border: 1px solid #dddde7;
		border-radius: 16px;

		&.speech {
			height: 83px;
		}

		.el-button {
			height: 48px;
			padding: 0;
			border-radius: 8px;
			transition: all 0.3s;
		}

		.send-button,
		.stop {
			background: rgb(29, 95, 250);
			border-color: rgb(29, 95, 250);
			width: 48px;
			font-size: 24px;
			margin-left: 12px;

			&:hover {
				background: rgba(29, 95, 250, 0.867);
				border-color: rgba(29, 95, 250, 0.867);
			}

			img {
				width: 32px;
				height: 32px;
			}
		}
		.send-button {
			display: flex;
			justify-content: center;
			align-items: center;
			position: relative;
			:deep(span) {
				position: absolute;
				left: 50%;
				top: 50%;
				transform: translate(-50%, -50%);
				margin: 0;
			}
		}

		.type-button {
			width: 48px;
			height: 48px;
			font-size: 24px;
			margin-right: 12px;
			background: #fff;
			border: 1px solid #ddd;
			border-radius: 8px;
			text-align: center;
			line-height: 46px;

			img {
				width: 32px;
				height: 32px;
			}
		}

		.stop {
			width: 48px !important;
			font-size: 24px;
		}

		.el-textarea {
			flex: 1;
			transition: width 0.2s;

			::v-deep(.el-textarea__inner) {
				padding: 14px;
				line-height: 20px;
				font-size: 14px;
				width: 100%;
				// height: 50px !important;
				min-height: 50px;
				box-sizing: border-box;
				border: 1px solid #ddd;
				resize: none;
				background: rgb(249, 249, 249);
				outline: none;
				border-radius: 8px;
				overflow-x: hidden;
			}
		}

		.play {
			// width: 60px;
			flex: 1;
			height: 48px;
			border-radius: 8px;
			background: rgb(29, 95, 250);
			border-color: rgb(29, 95, 250);
			color: #fff;
			display: flex;
			justify-content: center;
			font-size: 16px;
			line-height: 24px;
			padding: 12px;
			user-select: none;
			-webkit-user-select: none;
			-webkit-touch-callout: none;
			transition: all 0.3s;
			border: none;

			i {
				font-size: 24px;
				vertical-align: middle;
				margin-right: 12px;
			}

			&.speaking {
				box-shadow: 0 0 10px 0px rgb(29, 95, 250);
			}
		}
		:deep(.el-loading-mask) {
			background: #fff !important;
		}

		textarea::-webkit-input-placeholder {
			/* WebKit browsers */
			font-size: 14px;
			color: #9c9c9c;
			white-space: nowrap;
		}

		textarea:-moz-placeholder {
			/* Mozilla Firefox 4 to 18 */
			font-size: 14px;
			color: #9c9c9c;
		}

		textarea::-moz-placeholder {
			/* Mozilla Firefox 19+ */
			font-size: 14px;
			color: #9c9c9c;
		}

		textarea::-ms-input-placeholder {
			/* Internet Explorer 10+ */
			font-size: 14px;
			color: #9c9c9c;
		}
	}

	.speech-text {
		height: max-content;
		font-size: 16px;
		line-height: 20px;
		padding: 12px 12px 0;
		transition: height 0.2s;
	}

	.wave-wrap {
		width: 100%;
		height: 25px;
		display: flex;
		justify-content: center;
		align-items: center;
		gap: 8px;

		.wave {
			display: block;
			width: 6px;
			height: 6px;
			border-radius: 8px;
			background: #fff;

			&.active {
				animation: audio-wave 2s ease infinite;
				background: #ff8e3a;

				&:nth-child(1) {
					animation-delay: 0.1s;
				}

				&:nth-child(2) {
					animation-delay: 0.2s;
				}

				&:nth-child(3) {
					animation-delay: 0.3s;
				}

				&:nth-child(4) {
					animation-delay: 0.4s;
				}

				&:nth-child(5) {
					animation-delay: 0.5s;
				}
			}
		}
	}

	@keyframes audio-wave {
		0% {
			height: 6px;
			transform: translateY(0px);
			background: #ff8e3a;
		}

		25% {
			height: 6px;
			transform: translateY(2px);
			background: #9c73f8;
		}

		50% {
			height: 6px;
			transform: translateY(0px);
			background: #ed509e;
		}

		75% {
			height: 6px;
			transform: translateY(2px);
			background: #9c73f8;
		}

		100% {
			height: 6px;
			transform: translateY(0px);
			background: #ff8e3a;
			// background: #0fccce;
		}
	}

	.wave-animation {
		animation: wave-animation 2s infinite;
		width: 100px;
		height: 100px;
		background: blue;
		border-radius: 50%;
	}
}
</style>
